pub type Result<T> = std::result::Result<T, anyhow::Error>;
use crate::utils::preferences::AppInfo;
use optional_struct::optional_struct;
use optional_struct::Applyable;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

// local storage conifg file name
pub const P2PRPC_LOCAL_CONFIG_FILE_NAME: &str = "p2p_rpc_config";
// local unique deivce and unique userid config;
pub const USER_DEFAULT_LOCAL_CONFIG_FILE_NAME: &str = "user_default_config";
// local storage saved appinfo
pub const APP_INFO: AppInfo = AppInfo {
    name: "coolink_sdk",
    author: "coolink.coocaa.com",
};

#[optional_struct]
#[derive(Debug, Serialize, Deserialize)]
pub struct UserDefaultStorageConfig {
    pub user_default_ids_map: HashMap<String, String>,
}

impl OptionalUserDefaultStorageConfig {
    pub fn default() -> Self {
        OptionalUserDefaultStorageConfig {
            user_default_ids_map: None,
        }
    }
}

#[optional_struct]
#[derive(Debug, Serialize, Deserialize)]
pub struct P2PRPCLocalStorageConfig {
    pub group_lts_host_map: HashMap<String, String>,
    pub group_turn_host_map: HashMap<String, String>,
    pub group_nonce_map: HashMap<String, String>,
    pub group_unique_clinet_id_map: HashMap<String, String>,
    pub group_turn_user_map: HashMap<String, String>,
    pub group_turn_pwd_map: HashMap<String, String>,
}

impl OptionalP2PRPCLocalStorageConfig {
    pub fn default() -> Self {
        OptionalP2PRPCLocalStorageConfig {
            group_lts_host_map: None,
            group_turn_host_map: None,
            group_nonce_map: None,
            group_unique_clinet_id_map: None,
            group_turn_user_map: None,
            group_turn_pwd_map: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::model::storage_config::{
        OptionalP2PRPCLocalStorageConfig, OptionalUserDefaultStorageConfig,
        P2PRPCLocalStorageConfig, UserDefaultStorageConfig, APP_INFO,
        P2PRPC_LOCAL_CONFIG_FILE_NAME, USER_DEFAULT_LOCAL_CONFIG_FILE_NAME,
    };
    use crate::utils::logutil;
    use crate::utils::preferences::Preferences;
    use crate::utils::{ids, query};
    use std::path::PathBuf;
    #[test]
    fn test_storage_config() {
        logutil::global_log_init("coolink", "DEBUG");

        let config_store_path: PathBuf = "./".into();

        let mut user_config = OptionalUserDefaultStorageConfig::load(
            &APP_INFO,
            USER_DEFAULT_LOCAL_CONFIG_FILE_NAME,
            &config_store_path,
        )
        .map_err(|e| {
            log::warn!("load user default config err: {}", e.to_string());
            e
        })
        .unwrap_or(OptionalUserDefaultStorageConfig::default());
        let default_user_map = user_config.user_default_ids_map.get_or_insert_default();
        default_user_map.insert("user_id".to_owned(), "user_id".to_owned());
        default_user_map.insert("device_id".to_owned(), "device_id".to_owned());

        if let Err(e) = user_config.save(
            &APP_INFO,
            USER_DEFAULT_LOCAL_CONFIG_FILE_NAME,
            &config_store_path,
        ) {
            log::warn!("save user default config err: {:?}", e);
        } else {
            log::info!("save user default config Ok {:?}", &config);
        }

        let mut new_default_user_config = OptionalUserDefaultStorageConfig::load(
            &APP_INFO,
            USER_DEFAULT_LOCAL_CONFIG_FILE_NAME,
            &config_store_path,
        )
        .map_err(|e| {
            log::warn!("load user default config err: {}", e.to_string());
            e
        })
        .unwrap_or(OptionalUserDefaultStorageConfig::default());
        let new_default_user_map = new_default_user_config
            .user_default_ids_map
            .get_or_insert_default();
        assert_eq!(new_default_user_map.get("user_id").unwrap(), "user_id");
        assert_eq!(new_default_user_map.get("device_id").unwrap(), "device_id");

        let mut config = OptionalP2PRPCLocalStorageConfig::load(
            &APP_INFO,
            P2PRPC_LOCAL_CONFIG_FILE_NAME,
            &config_store_path,
        )
        .map_err(|e| {
            log::warn!("load config err: {}", e.to_string());
            e
        })
        .unwrap_or(OptionalP2PRPCLocalStorageConfig::default());
        let group_lts_host_map = config.group_lts_host_map.get_or_insert_default();
        let group_turn_host_map = config.group_turn_host_map.get_or_insert_default();
        let group_nonce_map = config.group_nonce_map.get_or_insert_default();
        let group_unique_client_id_map = config.group_unique_clinet_id_map.get_or_insert_default();
        let group_turn_user_map = config.group_turn_user_map.get_or_insert_default();
        let group_turn_pwd_map = config.group_turn_pwd_map.get_or_insert_default();

        group_lts_host_map.insert("test-key".to_owned(), "test-lts-address".to_owned());
        group_turn_host_map.insert("test-key".to_owned(), "test-turn-address".to_owned());
        group_nonce_map.insert("test-key".to_owned(), "test-nonce".to_owned());
        group_unique_client_id_map.insert("test-key".to_owned(), "test-server-id".to_owned());
        group_turn_user_map.insert("test-key".to_owned(), "test-turn-user".to_owned());
        group_turn_pwd_map.insert("test-key".to_owned(), "test-turn-pwd".to_owned());

        if let Err(e) = config.save(&APP_INFO, P2PRPC_LOCAL_CONFIG_FILE_NAME, &config_store_path) {
            log::warn!("save config err: {:?}", e);
        } else {
            log::info!("save config Ok {:?}", &config);
        }

        let mut new_config = OptionalP2PRPCLocalStorageConfig::load(
            &APP_INFO,
            P2PRPC_LOCAL_CONFIG_FILE_NAME,
            &config_store_path,
        )
        .map_err(|e| {
            log::warn!("load config err: {}", e.to_string());
            e
        })
        .unwrap_or(OptionalP2PRPCLocalStorageConfig::default());

        let group_lts_host_map = config.group_lts_host_map.get_or_insert_default();
        let group_turn_host_map = config.group_turn_host_map.get_or_insert_default();
        let group_nonce_map = config.group_nonce_map.get_or_insert_default();
        let group_unique_client_id_map = config.group_unique_clinet_id_map.get_or_insert_default();
        let group_turn_user_map = config.group_turn_user_map.get_or_insert_default();
        let group_turn_pwd_map = config.group_turn_pwd_map.get_or_insert_default();
        assert_eq!(
            group_lts_host_map.get("test-key").unwrap(),
            "test-lts-address"
        );
        assert_eq!(
            group_turn_host_map.get("test-key").unwrap(),
            "test-turn-address"
        );
        assert_eq!(group_nonce_map.get("test-key").unwrap(), "test-nonce");
        assert_eq!(
            group_turn_user_map.get("test-key").unwrap(),
            "test-turn-user"
        );
        assert_eq!(group_turn_pwd_map.get("test-key").unwrap(), "test-turn-pwd");
    }
}
